//
// Created by wuzhe on 2022/3/30.
//

#include "Player.hh"
#include "Console.h"
#include "Room.hh"
#include "state/OfflineState.h"

Player::Player(int num): Entity(num, EntityType::PLAYER),space(Space::getSingleton()) {
    INFO(std::string("创建角色entity:") + std::to_string(num));
    new OfflineState(*this);
}

void Player::createRoom(std::string roomName) {
    space.createRoom(roomName, this);

}

std::list<Room> Player::selectRoom(std::string roomName) {
    return std::list<Room>();
}

void Player::deleteRoom(int roomId) {

}

void Player::setRoleName(std::string roleName) {
    this->roleName = roleName;
}

void Player::sendMsg(std::string msg) {
    currentRoom->onTalk(std::move(msg), *this);
}

void Player::connect() {
    this->sendNeedRoleName();
}

void Player::reconnect() {
    space.send2Client(this, RECONNECT, "");
}

void Player::sendAck() {
    space.send2Client(this, ACK);
}

void Player::sendErr() {
    sendErr("invalid op");
}

void Player::sendErr(const std::string err) {
    errLog(std::string("player ") + IP + " " + err);
    space.send2Client(this, ERR, err);
}

void Player::sendNeedRoleName() {
    space.send2Client(this, NEED_ROLE);
}

Entity* Player::process(ParseRes &res) {
    unsigned type = (unsigned) res.head->type;
    switch (type) {
        case ENTER: {
            playerState->getEnter();
            break;
        }
        case CREATE_ROLE: {
            std::string roleName(res.content, res.len);
            playerState->getCreateRole(roleName);
            break;
        }
        case CREATE_ROOM: {
            std::string roomName(res.content, res.len);
            playerState->getCreateRoom(roomName);
            break;
        }
        case ROOM_LIST1: {
            std::string filter(res.content, res.len);
            space.sendRoomList(this, filter);
            break;
        }
        case ENTER_ROOM: {
            playerState->getEnterRoom(res.head->roomId);
            break;
        }
        case EXIT_ROOM: {
            playerState->getExitRoom(res.head->roomId);
            break;
        }
        case TALK: {
            std::string msg(res.content, res.len);
            playerState->getTalk(msg);
            break;
        }
        case HISTORY1: {
            this->getHistory();
            break;
        }
        case EXIT: {
            playerState->getExit();
            break;
        }
        default: {
            std::string msg("invalid type: ");
            msg += std::to_string(type);
            errLog(msg);
        }

    }
    return nullptr;
}

void Player::onEnterRoom(int i, bool isReconnect) {
    space.onEnterRoom(this, i);

    if (isReconnect) {
        reconnect();
    } else {
        sendAck();
    }
}
void Player::onExitRoom(int i) {
    if (i != currentRoom->roomId) {
        sendErr();
        return;
    }
    space.onExitRoom(this, i);
    sendAck();
}

void Player::doBroadcast(Msg msg) {
    space.send2Client(this, BROADCAST, msg.toString());
}

void Player::disconnect() {
    if (currentRoom != nullptr) {
        currentRoom->onPlayerQuit(this);
    }
}

Player::~Player() {
    this->disconnect();
    delete playerState;
}

void Player::getHistory() {
    if (currentRoom == nullptr) {
        return;
    }
    std::stringstream ss;
    std::deque<std::string> res = currentRoom->getHistory();
    for (int k = 0; k < res.size(); ++k) {
//        size_t i = str.find(':', 5);
        ss << res[res.size() - k - 1] << std::endl;
    }
    space.send2Client(this, HISTORY2, ss.str());
}

std::string Player::toString() {
    std::stringstream ss;
    switch (playerState->playerStatus) {
        case PLAYER_STATUS::OFFLINE: {
            ss << 0;
            break;
        }
        case PLAYER_STATUS::FIRST_LOGIN: {
            ss << 1;
            break;
        }
        case PLAYER_STATUS::ONLINE: {
            ss << 2;
            break;
        }
        case PLAYER_STATUS::IN_ROOM: {
            ss << 3 << ":" << currentRoom->roomId;
            break;
        }
    }
    return ss.str();
}

void Player::updatePlayerInfo() {
    space.updatePlayerInfo(this);
}

void Player::createRoomCB(Room *room) {
    if (room) {
        sendAck();
    } else {
        sendErr("房间名称已存在");
    }
}



